#include "auto_lstm_model_second.hh"

#include "iostream"
#include "stdlib.h"
#include "vector"
#include <stdio.h>

using namespace std;

RNN::~RNN()
{

}

RNN::RNN()
{
	y.resize(outnode);
}

void print_vf(vector<float>& a)
{
	for(int i = 0; i < a.size(); i ++) printf("%f\t", a[i]);
	puts("");
}

float pow_e[12] = {1.0039138794, 1.0078431368, 1.0157476664, 1.0317434072, 1.0644944906, 1.1331484318,
                1.2840254307, 1.6487212181, 2.7182817459, 7.3890562057, 54.5981483459, 2980.9580078125};
 

extern "C" void solve( 
	    int a,
            int b,
            int c,
            float* predict,
//            float x_testdata_window[time_step][innode],
	    float* x_testdata_window,
	    float* S_vector_layer1,
            float* H_vector_layer1,
            float* in_gate_layer1,
            float* out_gate_layer1,
            float* forget_gate_layer1,
            float* g_gate_layer1,
            float W_I_1[innode][hidenode_1],
            float U_I_1[hidenode_1][hidenode_1],
            float B_I_1[hidenode_1],
            float W_F_1[innode][hidenode_1],
            float U_F_1[hidenode_1][hidenode_1],
            float B_F_1[hidenode_1],
            float W_G_1[innode][hidenode_1],
            float U_G_1[hidenode_1][hidenode_1],
            float B_G_1[hidenode_1],
            float W_O_1[innode][hidenode_1],
            float U_O_1[hidenode_1][hidenode_1],
            float B_O_1[hidenode_1],
	    float pow_e[],
	    float W_out[hidenode_1][outnode],
	    float B_out[outnode]
	    );  

void RNN::rnn_predict(vector<float>& predict, float x_testdata_window[time_step][innode])
{

    Matrix<float> S_vector_layer1(hidenode_1,time_step+1); // 3 * (20 + 1)
    Matrix<float> H_vector_layer1(hidenode_1,time_step+1);

    vector<float> in_gate_layer1(hidenode_1);
    vector<float> out_gate_layer1(hidenode_1);
    vector<float> forget_gate_layer1(hidenode_1);
    vector<float> g_gate_layer1(hidenode_1);
    
    solve(   innode,
	     hidenode_1,
	     time_step,
	     0,
             &x_testdata_window[0][0],
             &S_vector_layer1.at(0, 0),
             &H_vector_layer1.at(0, 0),
             in_gate_layer1.data(),
             out_gate_layer1.data(),
             forget_gate_layer1.data(),
             g_gate_layer1.data(),
             W_I_1,
             U_I_1,
             B_I_1,
             W_F_1,
             U_F_1,
             B_F_1,
             W_G_1,
             U_G_1,
             B_G_1,
             W_O_1,
             U_O_1,
   	     B_O_1,
	     pow_e,
	     W_out,
	     B_out
	     );

// ------------------------------------------------------------------------------------

    Matrix<float> S_vector_layer2(hidenode_2,time_step+1);
    Matrix<float> H_vector_layer2(hidenode_2,time_step+1);
    
    vector<float> in_gate_layer2(hidenode_2);
    vector<float> out_gate_layer2(hidenode_2);
    vector<float> forget_gate_layer2(hidenode_2);
    vector<float> g_gate_layer2(hidenode_2);
             
    solve(   hidenode_1,
             hidenode_2,
             time_step,
             0,
             H_vector_layer1.line(1),
             &S_vector_layer2.at(0, 0),
             &H_vector_layer2.at(0, 0),
             in_gate_layer2.data(),
             out_gate_layer2.data(),
             forget_gate_layer2.data(),
             g_gate_layer2.data(),
             W_I_2,
             U_I_2,
             B_I_2,
             W_F_2,
             U_F_2,
             B_F_2,
             W_G_2,
             U_G_2,
             B_G_2,
             W_O_2,
             U_O_2,
             B_O_2,
	     pow_e,
	     W_out,
	     B_out
	     );
// --------------------------------------------------------------
    Matrix<float> S_vector_layer3(hidenode_3,time_step+1);
    Matrix<float> H_vector_layer3(hidenode_3,time_step+1);
    
    vector<float> in_gate_layer3(hidenode_3);
    vector<float> out_gate_layer3(hidenode_3);
    vector<float> forget_gate_layer3(hidenode_3);
    vector<float> g_gate_layer3(hidenode_3);
             
    solve(   hidenode_2,
             hidenode_3,
             time_step,
             0,
             H_vector_layer2.line(1),
             &S_vector_layer3.at(0, 0),
             &H_vector_layer3.at(0, 0),
             in_gate_layer3.data(),
             out_gate_layer3.data(),
             forget_gate_layer3.data(),
             g_gate_layer3.data(),
             W_I_3,
             U_I_3,
             B_I_3,
             W_F_3,
             U_F_3,
             B_F_3,
             W_G_3,
             U_G_3,
             B_G_3,
             W_O_3,
             U_O_3,
             B_O_3,
	     pow_e,
  	     W_out,
	     B_out	     
	     );

 // ------------------------------------------------------------------------------------   
    Matrix<float> S_vector_layer4(hidenode_4,time_step+1);
    Matrix<float> H_vector_layer4(hidenode_4,time_step+1);
    
    vector<float> in_gate_layer4(hidenode_4);
    vector<float> out_gate_layer4(hidenode_4);
    vector<float> forget_gate_layer4(hidenode_4);
    vector<float> g_gate_layer4(hidenode_4);
    
        solve(   
	     hidenode_3,
             hidenode_4,
             time_step,
             predict.data(),
             H_vector_layer3.line(1),
             &S_vector_layer4.at(0, 0),
             &H_vector_layer4.at(0, 0),
             in_gate_layer4.data(),
             out_gate_layer4.data(),
             forget_gate_layer4.data(),
             g_gate_layer4.data(),
             W_I_4,
             U_I_4,
             B_I_4,
             W_F_4,
             U_F_4,
             B_F_4,
             W_G_4,
             U_G_4,
             B_G_4,
             W_O_4,
             U_O_4,
             B_O_4,  
	     pow_e,
	     W_out,
	     B_out
	     );

    puts("exit solve");
   	print_vf(predict);
       /*	
     	print_vf(in_gate_layer4);
 	print_vf(out_gate_layer4);
 	print_vf(forget_gate_layer4);
 	print_vf(g_gate_layer4);
 	puts("");
 	for(int i = 0; i <= time_step; i ++)
 	{
 		for(int j = 0; j < hidenode_4; j ++)
 			printf("%f\t", S_vector_layer4.at(j, i));
 		puts("");
	 }
	 puts("");
	 for(int i = 0; i <= time_step; i ++)
 	 {
 		for(int j = 0; j < hidenode_4; j ++)
 			printf("%f\t", H_vector_layer4.at(j, i));
 		puts("");
	 }
	 */
    puts("exit for");	
    exit(0);
}

int main()
{
    RNN lstm;

    float x_input[time_step][innode] = {{0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},\
                                  {0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},\
                                  {0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},\
                                  {0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},\
                                  {0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1},{0.9,0.5,0.1}};

    vector<float>p(3);

    lstm.rnn_predict(p,x_input);

    return 0;
}
